package dongshi.daddy.seriablize;

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import dongshi.daddy.seriablize.avro.User;
import lombok.SneakyThrows;
import org.apache.avro.file.DataFileReader;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import org.junit.Test;
import org.nustaq.serialization.FSTConfiguration;

import java.io.*;

public class SerializeTest {

//    @SneakyThrows
//    public static void main(String[] args) {
//        testJavaSerialize();
//    }
    static FSTConfiguration configuration = FSTConfiguration
            // .createDefaultConfiguration();
            .createStructConfiguration();

    // fst序列化和反序列化
    @Test
    public void testFstSerializeAndDescrialize() {
        dongshi.daddy.seriablize.fst.User bean = new dongshi.daddy.seriablize.fst.User();
        bean.setUsername("xxxxx");
        bean.setPassword("123456");
        bean.setAge(1000000);
        byte[] byteBean = configuration.asByteArray(bean);
        System.out.println("序列化的字节大小是：" + byteBean.length);
        // 反序列化
        dongshi.daddy.seriablize.fst.User resultBean = (dongshi.daddy.seriablize.fst.User) configuration.asObject(byteBean);
        System.out.println("fst反序列化的结果是：" + resultBean);
    }

    String userDir = System.getProperty("user.dir");

    @Test
    public void testKrypDeserialize() throws Exception {
        Kryo kryo = new Kryo();
        kryo.register(SomeClass.class);

        Input input = new Input(new FileInputStream(userDir + "/someCls.bin"));
        SomeClass someClassFromBin = kryo.readObject(input, SomeClass.class);
        System.out.println(someClassFromBin.value);
    }

    @Test
    public void testKrypSerialize() throws Exception {
        Kryo kryo = new Kryo();
        kryo.register(SomeClass.class);

        SomeClass someClass = new SomeClass();
        someClass.value = "dongshidaddy";
        Output output = new Output(new FileOutputStream(userDir + "/someCls.bin"));
        kryo.writeObject(output, someClass);
        output.close();
    }

    static public class SomeClass {
        String value;
    }

    @Test
    public void testAvroDeserialize() throws Exception {
        DatumReader<User> reader = new SpecificDatumReader<User>(User.class);
        DataFileReader<User> dataFileReader = new DataFileReader<User>(new File(System.getProperty("user.dir") + "/User.avro"), reader);
        User user = null;
        while (dataFileReader.hasNext()) {
            user = dataFileReader.next();
            System.out.println(user);
        }
    }

    @Test
    public void xx() {
        System.out.println(System.getProperty("user.dir"));
    }

    // 测试avro的序列化和反序列化
    @Test
    public void testAvroSerialize() throws Exception {
// 声明并初始化User对象
        // 方式一
        User user1 = new User();
        user1.setName("wqbin");
        user1.setId(1);
        user1.setSalary(1000);
        user1.setAge(20);
        user1.setAddress("beijing");

        // 方式二 使用构造函数
// Alternate constructor
        User user2 = new User("wang", 2, 1000, 19, "guangzhou");

// 方式三，使用Build方式
// Construct via builder
        User user3 = User.newBuilder()
                .setName("bin")
                .setId(3)
                .setAge(21)
                .setSalary(2000)
                .setAddress("shenzhen")
                .build();
        String userDir = System.getProperty("user.dir");
        System.out.println("userDir is: " + userDir);
        String path = userDir + "/User.avro"; // avro文件存放目录
        DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class);
        DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);
        dataFileWriter.create(user1.getSchema(), new File(path));
// 把生成的user对象写入到avro文件
        dataFileWriter.append(user1);
        dataFileWriter.append(user2);
        dataFileWriter.append(user3);
        dataFileWriter.close();
    }

    // 测试hessian的序列化和反序列化
    @Test
    public void testHessianSerialize() throws IOException {
        hessianSerialize();
    }

    private void hessianSerialize() {
        Student stu = new Student("hessian", 1);
        byte[] obj = serialize(stu);
        System.out.println("hessian serialize result length = " + obj.length);
        byte[] obj2 = serialize2(stu);
        System.out.println("hessian2 serialize result length = " + obj2.length);
        byte[] other = jdkSerialize(stu);
        System.out.println("jdk serialize result length = " + other.length);
        Student student = deserialize2(obj2);
        System.out.println("deserialize result entity is " + student);
    }


    // 测试Java的序列化和反序列化 transient和static关键字修饰的变量不会被序列化,特别是transient
    @Test
    public void testJavaSerialize() throws IOException {
        javaSerialize();
        javaDeserialize();
    }

    public static <T> byte[] serialize(T t) {
        byte[] data = null;
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            HessianOutput output = new HessianOutput(os);
            output.writeObject(t);
            data = os.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    public static <T> byte[] serialize2(T t) {
        byte[] data = null;
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            Hessian2Output output = new Hessian2Output(os);
            output.writeObject(t);
            output.getBytesOutputStream().flush();
            output.completeMessage();
            output.close();
            data = os.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    public static <T> byte[] jdkSerialize(T t) {
        byte[] data = null;
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ObjectOutputStream output = new ObjectOutputStream(os);
            output.writeObject(t);
            output.flush();
            output.close();
            data = os.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    @SuppressWarnings("unchecked")
    public static <T> T deserialize(byte[] data) {
        if (data == null) {
            return null;
        }
        Object result = null;
        try {
            ByteArrayInputStream is = new ByteArrayInputStream(data);
            HessianInput input = new HessianInput(is);
            result = input.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) result;
    }

    @SuppressWarnings("unchecked")
    public static <T> T deserialize2(byte[] data) {
        if (data == null) {
            return null;
        }
        Object result = null;
        try {
            ByteArrayInputStream is = new ByteArrayInputStream(data);
            Hessian2Input input = new Hessian2Input(is);
            result = input.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) result;
    }

    @SneakyThrows
    private static void javaDeserialize() {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("d:\\test\\xxx.obj"));
        Student student = (Student) objectInputStream.readObject();
        System.out.println("java反序列化student完成");
        System.out.println(student);
    }

    @SneakyThrows
    private static void javaSerialize() throws IOException {
        Student student = new Student();
        student.setName("张三");
        student.setAge(99);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("d:\\test\\xxx.obj"));
        // 如果没有实现java.io.Serializable接口将会抛出异常java.io.NotSerializableException
        objectOutputStream.writeObject(student);
        objectOutputStream.close();
        System.out.println("java序列化student完成");
    }
}
// 测试avro的反序列化
